/*
 * Copyright (c) 2018. paascloud.net All Rights Reserved.
 * 项目名称：paascloud快速搭建企业级分布式微服务平台
 * 类名称：MdcDictServiceImpl.java
 * 创建人：刘兆明
 * 联系方式：paascloud.net@gmail.com
 * 开源地址: https://github.com/paascloud
 * 博客地址: http://blog.paascloud.net
 * 项目官网: http://paascloud.net
 */

package com.csun.cmny.provider.service.impl;

import com.csun.cmny.base.dto.LoginAuthDto;
import com.csun.cmny.base.dto.UpdateStatusDto;
import com.csun.cmny.base.enums.ErrorCodeEnum;
import com.csun.cmny.core.support.BaseService;
import com.csun.cmny.core.support.TreeUtils;
import com.csun.cmny.provider.exceptions.MdcBizException;
import com.csun.cmny.provider.mapper.MdcDictMapper;
import com.csun.cmny.provider.model.domain.MdcDict;
import com.csun.cmny.provider.model.dto.MdcDictCheckCodeDto;
import com.csun.cmny.provider.model.dto.MdcDictCheckKeyValueDto;
import com.csun.cmny.provider.model.dto.MdcDictCheckNameDto;
import com.csun.cmny.provider.model.dto.MdcDictQueryDto;
import com.csun.cmny.provider.model.enums.MdcDictStatusEnum;
import com.csun.cmny.provider.model.vo.MdcDictVo;
import com.csun.cmny.provider.resolver.CmnyMessageSource;
import com.csun.cmny.provider.service.MdcDictService;
import com.csun.cmny.provider.utils.TreeUtil;
import com.csun.cmny.util.PublicUtil;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.modelmapper.ModelMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.List;

/**
 * The class Mdc dict service.
 *
 * @author paascloud.net @gmail.com
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MdcDictServiceImpl extends BaseService<MdcDict> implements MdcDictService {
	@Resource
	private MdcDictMapper mdcDictMapper;
	@Resource
	private CmnyMessageSource cmnyMessageSource;

	@Override
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	public List<MdcDictVo> getDictTreeList() {
		List<MdcDictVo> list = mdcDictMapper.listDictVo();
		return new TreeUtils().getChildTreeObjects(list, 0L);
	}

	@Override
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	public MdcDictVo getMdcDictVoById(Long dictId) {
		MdcDict dict = mdcDictMapper.selectByPrimaryKey(dictId);

		if (dict == null) {
			logger.error("找不到数据字典信息id={}", dictId);
			throw new MdcBizException(ErrorCodeEnum.MDC10021018, dictId);
		}

		// 获取父级菜单信息
		MdcDict parentDict = mdcDictMapper.selectByPrimaryKey(dict.getPid());

		ModelMapper modelMapper = new ModelMapper();
		MdcDictVo dictVo = modelMapper.map(dict, MdcDictVo.class);

		if (parentDict != null) {
			dictVo.setParentDictName(parentDict.getDictName());
		}

		return dictVo;
	}

	@Override
	public void updateMdcDictStatusById(UpdateStatusDto updateStatusDto, LoginAuthDto loginAuthDto) {
		Long id = updateStatusDto.getId();
		Integer status = updateStatusDto.getStatus();
		// 要处理的菜单集合
		List<MdcDict> mdcDictList = Lists.newArrayList();

		int result;
		if (status.equals(MdcDictStatusEnum.DISABLE.getType())) {
			// 获取菜单以及子菜单
			mdcDictList = this.getAllDictFolder(id, MdcDictStatusEnum.ENABLE.getType());
		} else {
			// 获取菜单、其子菜单以及父菜单
			MdcDict uacMenu = new MdcDict();
			uacMenu.setPid(id);
			result = this.selectCount(uacMenu);
			// 此菜单含有子菜单
			if (result > 0) {
				mdcDictList = this.getAllDictFolder(id, MdcDictStatusEnum.DISABLE.getType());
			}
			List<MdcDict> dictListTemp = this.getAllParentDictFolderByMenuId(id);
			for (MdcDict dict : dictListTemp) {
				if (!mdcDictList.contains(dict)) {
					mdcDictList.add(dict);
				}
			}
		}

		this.updateDictStatus(mdcDictList, loginAuthDto, status);
	}

	private void updateDictStatus(List<MdcDict> mdcDictList, LoginAuthDto loginAuthDto, int status) {
		MdcDict update = new MdcDict();
		for (MdcDict dict : mdcDictList) {
			update.setId(dict.getId());
			update.setVersion(dict.getVersion() + 1);
			update.setStatus(status);
			update.setUpdateInfo(loginAuthDto);
			int result = mapper.updateByPrimaryKeySelective(update);
			if (result < 1) {
				throw new MdcBizException(ErrorCodeEnum.MDC10021019, dict.getId());
			}
		}
	}

	private List<MdcDict> getAllDictFolder(Long id, int dictStatus) {
		MdcDict mdcDict = new MdcDict();
		mdcDict.setId(id);
		mdcDict = mapper.selectOne(mdcDict);
		List<MdcDict> mdcDictList = Lists.newArrayList();
		mdcDictList = buildNode(mdcDictList, mdcDict, dictStatus);
		return mdcDictList;
	}

	private List<MdcDict> getAllParentDictFolderByMenuId(Long dictId) {
		MdcDict mdcDictQuery = new MdcDict();
		mdcDictQuery.setId(dictId);
		mdcDictQuery = mapper.selectOne(mdcDictQuery);
		List<MdcDict> mdcDictList = Lists.newArrayList();
		mdcDictList = buildParentNote(mdcDictList, mdcDictQuery);
		return mdcDictList;
	}

	/**
	 * 递归获取菜单的子节点
	 */
	private List<MdcDict> buildNode(List<MdcDict> mdcDictList, MdcDict uacMenu, int dictStatus) {
		List<MdcDict> uacMenuQueryList = mapper.select(uacMenu);
		MdcDict uacMenuQuery;
		for (MdcDict dict : uacMenuQueryList) {
			if (dictStatus == dict.getStatus()) {
				mdcDictList.add(dict);
			}
			uacMenuQuery = new MdcDict();
			uacMenuQuery.setPid(dict.getId());
			buildNode(mdcDictList, uacMenuQuery, dictStatus);
		}
		return mdcDictList;
	}

	/**
	 * 递归获取菜单的父菜单
	 */
	private List<MdcDict> buildParentNote(List<MdcDict> mdcDictList, MdcDict mdcDict) {
		List<MdcDict> mdcDictQueryList = mapper.select(mdcDict);
		MdcDict uacMenuQuery;
		for (MdcDict dict : mdcDictQueryList) {
			if (MdcDictStatusEnum.DISABLE.getType() == dict.getStatus()) {
				mdcDictList.add(dict);
			}
			uacMenuQuery = new MdcDict();
			uacMenuQuery.setId(dict.getPid());
			buildParentNote(mdcDictList, uacMenuQuery);
		}
		return mdcDictList;
	}

	@Override
	public void saveMdcDict(MdcDict mdcDict, LoginAuthDto loginAuthDto) {
		Long pid = mdcDict.getPid();
		mdcDict.setUpdateInfo(loginAuthDto);
		MdcDict parentMenu = mapper.selectByPrimaryKey(pid);
		if (PublicUtil.isEmpty(parentMenu)) {
			throw new MdcBizException(ErrorCodeEnum.MDC10021020, pid);
		}

		if (parentMenu.getType().equals(1)) {
			throw new MdcBizException(ErrorCodeEnum.MDC10021028);
		}

		MdcDictCheckCodeDto mdcDictCheckCodeDto;
		MdcDictCheckNameDto mdcDictCheckNameDto;
		MdcDictCheckKeyValueDto mdcDictCheckKeyValueDto;
		if (mdcDict.isNew()) {
			MdcDict updateMenu = new MdcDict();
			updateMenu.setId(pid);

			// 校验编码不能重复
			mdcDictCheckCodeDto = new MdcDictCheckCodeDto();
			mdcDictCheckCodeDto.setDictCode(mdcDict.getDictCode());
			if (!checkDictCode(mdcDictCheckCodeDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021026);
			}

			// 校验名称不能重复
			mdcDictCheckNameDto = new MdcDictCheckNameDto();
			mdcDictCheckNameDto.setDictName(mdcDict.getDictName());
			if (!checkDictName(mdcDictCheckNameDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021027);
			}

			/**
			 * @date	2020-04-20
			 * @author	chisj
			 * @desc	校验key-value
			 */
			mdcDictCheckKeyValueDto = new MdcDictCheckKeyValueDto();
			mdcDictCheckKeyValueDto.setDictKey(mdcDict.getDictKey());
			mdcDictCheckKeyValueDto.setDictValue(mdcDict.getDictValue());
			if (!checkDictKeyValue(mdcDictCheckKeyValueDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021029);
			}

			mapper.insertSelective(mdcDict);
		} else {

			// 校验编码不能重复
			mdcDictCheckCodeDto = new MdcDictCheckCodeDto();
			mdcDictCheckCodeDto.setDictId(mdcDict.getId());
			mdcDictCheckCodeDto.setDictCode(mdcDict.getDictCode());
			if (!checkDictCode(mdcDictCheckCodeDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021026);
			}

			// 校验名称不能重复
			mdcDictCheckNameDto = new MdcDictCheckNameDto();
			mdcDictCheckNameDto.setDictId(mdcDict.getId());
			mdcDictCheckNameDto.setDictName(mdcDict.getDictName());
			if (!checkDictName(mdcDictCheckNameDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021027);
			}

			/**
			 * @date	2020-04-20
			 * @author	chisj
			 * @desc	校验key-value
			 */
			mdcDictCheckKeyValueDto = new MdcDictCheckKeyValueDto();
			mdcDictCheckKeyValueDto.setDictId(mdcDict.getId());
			mdcDictCheckKeyValueDto.setDictKey(mdcDict.getDictKey());
			mdcDictCheckKeyValueDto.setDictValue(mdcDict.getDictValue());
			if (!checkDictKeyValue(mdcDictCheckKeyValueDto)) {
				new MdcBizException(ErrorCodeEnum.MDC10021029);
			}

			mapper.updateByPrimaryKeySelective(mdcDict);
		}

	}

	@Override
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	public boolean checkDictHasChildDict(Long dictId) {
		logger.info("检查数据字典id={}是否存在生效节点", dictId);
		MdcDict uacMenu = new MdcDict();
		uacMenu.setStatus(MdcDictStatusEnum.ENABLE.getType());
		uacMenu.setPid(dictId);

		return mapper.selectCount(uacMenu) > 0;
	}

	/**
	 * query dict and sub by id
	 *
	 * @param id	the id
	 *
	 * @return	the mdc dict vo
	 */
	@Override
	public MdcDictVo queryDictAndSubById(Long id) {

		MdcDict dict = mdcDictMapper.selectByPrimaryKey(id);

		if (dict == null) {
			logger.error("找不到数据字典信息id={}", id);
			throw new MdcBizException(ErrorCodeEnum.MDC10021018, id);
		}

		MdcDictVo dictVo = new MdcDictVo();
		BeanUtils.copyProperties(dict, dictVo);

		// 根据Id查询该节点及所有的子节点
		List<Long> idList = queryIdListById(id);
		if (PublicUtil.isEmpty(idList)) {
			return dictVo;
		}

		//
		List<MdcDictVo> mdcDictVoList = queryListByIdList(idList);
		if (PublicUtil.isEmpty(mdcDictVoList)) {
			return dictVo;
		}

		// 转树结构
		List<MdcDictVo> mdcDictVos =  TreeUtil.getChildDictVos(mdcDictVoList, id);
		if (PublicUtil.isEmpty(mdcDictVos)) {
			return dictVo;
		}

		dictVo.setChildren(mdcDictVos);

		return dictVo;
	}

	/**
	 * query dict sub list with page
	 *
	 * @param mdcDictQueryDto the mdc dict query dto
	 * @return the list.
	 */
	@Override
	public List<MdcDictVo> queryDictSubListWithPage(MdcDictQueryDto mdcDictQueryDto) {

		Long pid = mdcDictQueryDto.getPid();

		// 校验Id不能为空
		Preconditions.checkArgument(pid != null,
				cmnyMessageSource.getMessage("dict.pid.null", null));

		MdcDict mdcDict = mdcDictMapper.selectByPrimaryKey(pid);
		if (mdcDict == null) {
			new MdcBizException(ErrorCodeEnum.MDC10021018);
		}

		// 分页
		PageHelper.startPage(mdcDictQueryDto.getPageNum(), mdcDictQueryDto.getPageSize());

		mdcDictQueryDto.setType(0);
		// 根据Id查询下一层
		return mdcDictMapper.queryDictListWithPage(mdcDictQueryDto);
	}

	/**
	 * query dict sub list by dict code
	 *
	 * @param dictCode the dict code
	 * @return the list.
	 */
	@Override
	public List<MdcDictVo> queryDictSubListByDictCode(String dictCode) {

		MdcDictCheckCodeDto mdcDictCheckCodeDto = new MdcDictCheckCodeDto();
		mdcDictCheckCodeDto.setDictCode(dictCode);
		if (checkDictCode(mdcDictCheckCodeDto)) {
			new MdcBizException(ErrorCodeEnum.MDC10021025);
		}

		MdcDict mdcDict = new MdcDict();
		mdcDict.setDictCode(dictCode);
		mdcDict = mdcDictMapper.selectOne(mdcDict);
		if (mdcDict == null) {
			new MdcBizException(ErrorCodeEnum.MDC10021025);
		}

		if (mdcDict.getType().equals(1)) {
			return null;
		}

		return mdcDictMapper.queryDictSubListByPid(mdcDict.getId());
	}

	/**
	 * check dict code
	 *
	 * @param mdcDictCheckCodeDto mdc dict check code dto
	 * @return the boolean true-没有重复 false-存在重复
	 */
	@Override
	public boolean checkDictCode(MdcDictCheckCodeDto mdcDictCheckCodeDto) {

		Long id = mdcDictCheckCodeDto.getDictId();
		String dictCode = mdcDictCheckCodeDto.getDictCode();

		Example example = new Example(MdcDict.class);
		Example.Criteria criteria = example.createCriteria();

		if (id != null) {
			criteria.andNotEqualTo("id", id);
		}
		criteria.andEqualTo("dictCode", dictCode);

		int result = mdcDictMapper.selectCountByExample(example);

		return result < 1;
	}

	/**
	 * check dict name
	 *
	 * @param mdcDictCheckNameDto mdc dict check name dto
	 * @return
	 */
	@Override
	public boolean checkDictName(MdcDictCheckNameDto mdcDictCheckNameDto) {

		Long id = mdcDictCheckNameDto.getDictId();
		String dictName = mdcDictCheckNameDto.getDictName();

		Example example = new Example(MdcDict.class);
		Example.Criteria criteria = example.createCriteria();

		if (id != null) {
			criteria.andNotEqualTo("id", id);
		}
		criteria.andEqualTo("dictName", dictName);

		int result = mdcDictMapper.selectCountByExample(example);

		return result < 1;
	}

	/**
	 * check dict check key value dto
	 *
	 * @param mdcDictCheckKeyValueDto	the mdc dict check value dto
	 *
	 * @return	the boolean
	 */
	@Override
	public boolean checkDictKeyValue(MdcDictCheckKeyValueDto mdcDictCheckKeyValueDto) {

		Long id = mdcDictCheckKeyValueDto.getDictId();
		String dictKey = mdcDictCheckKeyValueDto.getDictKey();
		String dictValue = mdcDictCheckKeyValueDto.getDictValue();

		Example example = new Example(MdcDict.class);
		Example.Criteria criteria = example.createCriteria();

		if (id != null) {
			criteria.andNotEqualTo("id", id);
		}
		criteria.andEqualTo("dictKey", dictKey);
		criteria.andEqualTo("dictValue", dictValue);

		int result = mdcDictMapper.selectCountByExample(example);

		return result < 1;
	}

	private List<MdcDictVo> queryListByIdList(List<Long> idList) {

		return mdcDictMapper.queryListByIdList(idList);
	}

	private List<Long> queryIdListById(Long id) {

		return mdcDictMapper.queryIdListById(id);
	}

}